Skip to content

05 配置管理与App Factory

前面几篇文章中,我们写死了不少东西:端口号、Debug模式、Agent模型名……在开发阶段这没问题,但一旦要部署到生产环境,你就需要区分不同的配置——开发环境开Debug,生产环境关Debug;开发用SQLite,生产用MySQL;API Key不能写死在代码里。

这篇文章就来解决两个问题:怎么管理配置怎么组织应用创建流程

一、配置基础

Flask的配置就是一个字典,挂在app.config上:

python
app = Flask(__name__)

# 像字典一样操作
app.config["SECRET_KEY"] = "my-secret-key"
app.config["DEBUG"] = True

# 批量更新
app.config.update(
    DEBUG=True,
    SECRET_KEY="my-secret-key",
)

配置的key必须是大写,这是Flask的约定。小写的key会被忽略。

1.1 常用配置项

配置项说明默认值
DEBUG是否开启调试模式False
SECRET_KEY用于签名Session等的密钥None
TESTING测试模式,异常会直接抛出False
MAX_CONTENT_LENGTH请求体最大字节数None(不限制)

对于Agent项目,你可能还需要自定义配置:

python
app.config.update(
    # Flask内置
    SECRET_KEY="your-secret-key",

    # Agent相关(自定义)
    DEFAULT_MODEL="deepseek-v4-flash",
    MAX_HISTORY=50,
    API_KEY="sk-xxxx",
)

二、从文件加载配置

把配置写在代码里不太安全——API Key可能会被提交到Git。更好的做法是把配置放在单独的文件里。

2.1 从Python文件加载

创建一个config.py

python
# config.py
SECRET_KEY = "my-secret-key"
DEBUG = True
DEFAULT_MODEL = "deepseek-v4-flash"
MAX_HISTORY = 50

然后在应用中加载:

python
app = Flask(__name__)
app.config.from_pyfile("config.py")

from_pyfile会读取Python文件中所有大写名称的变量。

2.2 从对象加载

如果你更喜欢用类来组织配置,可以用from_object

python
# config.py
class Config:
    SECRET_KEY = "my-secret-key"
    DEFAULT_MODEL = "deepseek-v4-flash"
    MAX_HISTORY = 50

class DevelopmentConfig(Config):
    DEBUG = True

class ProductionConfig(Config):
    DEBUG = False
python
app = Flask(__name__)
app.config.from_object("config.DevelopmentConfig")

from_object只是读取对象的属性,不会实例化类。所以用类属性就够了。

2.3 从环境变量加载

最安全的方式——配置通过环境变量传入,代码里不出现任何密钥:

bash
# 设置环境变量(FLASK_前缀是固定的)
export FLASK_SECRET_KEY="my-secret-key"
export FLASK_DEFAULT_MODEL="deepseek-v4-flash"
export FLASK_MAX_HISTORY=50
python
app = Flask(__name__)
app.config.from_prefixed_env()

加载后,app.config["SECRET_KEY"]就是"my-secret-key"——前缀FLASK_会被自动去掉。

支持嵌套配置,用双下划线分隔:

bash
export FLASK_DATABASE__HOST="localhost"
export FLASK_DATABASE__PORT=5432
python
app.config["DATABASE"]["HOST"]  # "localhost"
app.config["DATABASE"]["PORT"]  # 5432

2.4 从JSON/TOML文件加载

也可以用其他格式的配置文件:

python
import json
import tomllib

# 从JSON加载
app.config.from_file("config.json", load=json.load)

# 从TOML加载
app.config.from_file("config.toml", load=tomllib.load, text=False)

三、多环境配置

实际项目中,至少需要两套配置:开发环境和生产环境。用类继承的方式最清晰:

python
# config.py
class Config:
    """基础配置"""
    SECRET_KEY = "change-me-in-production"
    DEFAULT_MODEL = "deepseek-v4-flash"
    MAX_HISTORY = 50


class DevelopmentConfig(Config):
    """开发环境"""
    DEBUG = True


class ProductionConfig(Config):
    """生产环境"""
    DEBUG = False


# 配置映射,方便通过名称查找
config_map = {
    "development": DevelopmentConfig,
    "production": ProductionConfig,
}

通过环境变量切换:

python
import os
from config import config_map

env = os.environ.get("FLASK_ENV", "development")
app.config.from_object(config_map[env])
bash
# 开发环境(默认)
python app.py

# 生产环境
FLASK_ENV=production python app.py

四、App Factory模式

前面我们一直在用app = Flask(__name__)直接创建应用。这种方式在小项目中没问题,但有几个问题:

  1. 测试不方便:想测试不同配置,没法创建多个应用实例
  2. 循环引用:其他模块import app时容易出问题
  3. 初始化顺序:扩展和蓝图的注册逻辑散落各处

App Factory(应用工厂)模式就是把创建应用的过程封装到一个函数里:

python
def create_app():
    app = Flask(__name__)

    # 加载配置
    app.config.from_prefixed_env()

    # 注册蓝图
    from routes.chat import chat_bp
    from routes.session import session_bp
    from routes.health import health_bp
    app.register_blueprint(chat_bp, url_prefix="/api")
    app.register_blueprint(session_bp, url_prefix="/api")
    app.register_blueprint(health_bp)

    # 注册错误处理
    from errors import register_error_handlers
    register_error_handlers(app)

    return app

启动时调用工厂函数:

python
# app.py
if __name__ == "__main__":
    app = create_app()
    app.run()

4.1 为什么叫"工厂"

因为这个函数就像工厂一样,每次调用都能生产一个新的应用实例。你可以生产不同配置的实例:

python
# 生产环境的实例
prod_app = create_app()

# 测试用的实例
test_app = create_app()
test_app.config["TESTING"] = True

4.2 Flask自动发现

Flask命令行工具能自动识别名为create_appmake_app的工厂函数:

bash
# Flask会自动找到create_app
flask --app app run

# 也可以指定参数
flask --app 'app:create_app(debug=True)' run

4.3 配合扩展

App Factory模式下,扩展的初始化要用init_app而不是直接传app

python
# 创建扩展对象(不绑定应用)
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    app.config.from_prefixed_env()

    # 绑定扩展到应用
    db.init_app(app)

    return app

这样同一个扩展对象可以绑定到不同的应用实例。

五、完整项目结构

把App Factory和配置管理结合起来,一个标准的Agent API项目结构:

my-agent-api/
├── app.py              # 工厂函数 + 启动入口
├── config.py           # 多环境配置
├── routes/
│   ├── __init__.py
│   ├── chat.py
│   ├── session.py
│   └── health.py
├── errors.py           # 错误处理
└── .env                # 环境变量(不要提交到Git)

5.1 config.py

python
# config.py
import os


class Config:
    SECRET_KEY = os.environ.get("SECRET_KEY", "dev-secret-key")
    DEFAULT_MODEL = os.environ.get("DEFAULT_MODEL", "deepseek-v4-flash")
    MAX_HISTORY = int(os.environ.get("MAX_HISTORY", 50))


class DevelopmentConfig(Config):
    DEBUG = True


class ProductionConfig(Config):
    DEBUG = False


config_map = {
    "development": DevelopmentConfig,
    "production": ProductionConfig,
}

5.2 app.py

python
# app.py
import os
from flask import Flask
from config import config_map


def create_app():
    env = os.environ.get("FLASK_ENV", "development")
    app = Flask(__name__)
    app.config.from_object(config_map[env])
    app.config.from_prefixed_env()

    # 注册蓝图
    from routes.chat import chat_bp
    from routes.session import session_bp
    from routes.health import health_bp
    app.register_blueprint(chat_bp, url_prefix="/api")
    app.register_blueprint(session_bp, url_prefix="/api")
    app.register_blueprint(health_bp)

    # 注册错误处理
    from errors import register_error_handlers
    register_error_handlers(app)

    return app


if __name__ == "__main__":
    app = create_app()
    app.run()

5.3 在蓝图中访问配置

Blueprint中不能直接访问app.config,需要用Flask提供的current_app代理:

python
from flask import Blueprint, current_app

chat_bp = Blueprint("chat", __name__)

@chat_bp.route("/chat", methods=["POST"])
def chat():
    model = current_app.config["DEFAULT_MODEL"]
    return {"model": model}

current_app会自动指向当前处理请求的应用实例,在请求之外访问会报错。

六、.env文件

开发阶段,可以用python-dotenv自动加载.env文件中的环境变量,不用每次手动export

bash
pip install python-dotenv

创建.env文件:

FLASK_ENV=development
SECRET_KEY=dev-secret-key
DEFAULT_MODEL=deepseek-v4-flash

Flask会自动读取项目根目录的.env文件(需要安装python-dotenv)。

注意:.env文件不要提交到Git。在.gitignore中加上:

.env

七、总结

配置管理和App Factory是Flask项目从"能跑"到"能维护"的关键:

  • 配置加载from_pyfile(Python文件)、from_object(类)、from_prefixed_env(环境变量)
  • 多环境:用类继承区分dev/prod,通过环境变量切换
  • App Factory:把创建应用封装到create_app()函数,方便测试和扩展
  • current_app:在蓝图中通过代理访问应用配置
  • .env文件:开发时自动加载环境变量,不要提交到Git

在下一篇文章中,我们将学习错误处理与日志——当你的Agent API出了问题,怎么快速定位和修复。